package com.wang.lottery.infrastucture.repository;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wang.lottery.common.Constants;
import com.wang.lottery.domain.activity.model.po.Activity;
import com.wang.lottery.domain.activity.model.po.Award;
import com.wang.lottery.domain.activity.model.po.UserTakeActivityCount;
import com.wang.lottery.domain.activity.model.req.PartakeReq;
import com.wang.lottery.domain.activity.model.res.StockResult;
import com.wang.lottery.domain.activity.model.vo.ActivityBillVO;
import com.wang.lottery.domain.activity.model.vo.ActivityPartakeRecordVO;
import com.wang.lottery.domain.activity.model.vo.ActivityVO;
import com.wang.lottery.domain.activity.repository.IActivityRepository;
import com.wang.lottery.domain.award.model.vo.AwardVO;
import com.wang.lottery.domain.strategy.model.po.Strategy;
import com.wang.lottery.domain.strategy.model.po.StrategyDetail;
import com.wang.lottery.domain.strategy.model.vo.StrategyDetailVO;
import com.wang.lottery.domain.strategy.model.vo.StrategyVO;
import com.wang.lottery.domain.strategy.repository.IStrategyDetailRepository;
import com.wang.lottery.domain.strategy.repository.IStrategyRepository;
import com.wang.lottery.infrastucture.mapper.ActivityMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author wjh
 * @create 2023-11-04 15:31
 * 活动仓储服务
 */
@Component
@Slf4j
public class ActivityRepository extends ServiceImpl<ActivityMapper,Activity> implements IActivityRepository {
    
    @Resource
    private IStrategyRepository strategyRepository;
    @Resource
    private IStrategyDetailRepository strategyDetailRepository;
    
    @Resource
    private UserTakeActivityCountRepository userTakeActivityCountRepository;
    @Resource
    private UserTakeActivityRepository userTakeActivityRepository;
    @Resource
    private RedisTemplate<String,Object> redisTemplate;
    


    /**
     * 添加活动配置
     *
     * @param activityVO 活动配置
     */
    @Override
    public void add(ActivityVO activityVO) {
        Activity activity = new Activity();
        BeanUtils.copyProperties(activityVO,activity);
        baseMapper.insert(activity);
    }

    /**
     * 添加奖品配置集合
     *
     * @param awardVOList 奖品配置集合
     */
    @Override
    public void addAward(List<AwardVO> awardVOList) {
        List<Award> awardList = new ArrayList<>(awardVOList.size());
        for (AwardVO awardVo : awardVOList) {
            Award award = new Award();
            BeanUtils.copyProperties(awardVo,award);
            awardList.add(award);
        }
        baseMapper.insertList(awardList);
    }

    /**
     * 添加策略配置集合
     *
     * @param strategyVO 策略配置
     */
    @Override
    public void addStrategy(StrategyVO strategyVO) {
        Strategy strategy = new Strategy();
        BeanUtils.copyProperties(strategyVO,strategy);
        strategy.setCreateTime(new Date());
        strategy.setUpdateTime(strategy.getCreateTime());
        strategyRepository.save(strategy);

    }

    /**
     * 添加策略明细配置
     *
     * @param strategyDetailVOList 策略明细集合
     */
    @Override
    public void addStrategyDetailList(List<StrategyDetailVO> strategyDetailVOList) {
        List<StrategyDetail> strategyDetailList = new ArrayList<>(strategyDetailVOList.size());
        for (StrategyDetailVO strategyDetailVO : strategyDetailVOList) {
            StrategyDetail strategyDetail = new StrategyDetail();
            BeanUtils.copyProperties(strategyDetailVO,strategyDetail);
            strategyDetail.setCreateTime(new Date());
            strategyDetail.setUpdateTime(strategyDetail.getCreateTime());
            strategyDetailList.add(strategyDetail);
        }
        strategyDetailRepository.saveBatch(strategyDetailList);
    }


    /**
     * 变更活动状态
     *
     * @param activityId  活动ID
     * @param beforeState 修改前状态
     * @param afterState  修改后状态
     * @return 更新结果
     */
    @Override
    public boolean alterStatus(Long activityId, Constants.ActivityState beforeState, Constants.ActivityState afterState) {
        LambdaUpdateWrapper<Activity> updateWrapper = Wrappers.<Activity>lambdaUpdate().eq(Activity::getActivityId, activityId)
                .eq(Activity::getState, beforeState.getCode())
                .setSql("state = " + afterState.getCode());
        Activity activity = Activity.builder().activityId(activityId).state(beforeState.getCode()).build();
        int update = baseMapper.update(activity, updateWrapper);
        return update == 1;
    }

    /**
     * 查询活动账单信息【库存、状态、日期、个人参与次数】
     *
     * @param req 参与请求参数
     * @return 活动账单
     */
    @Override
    public ActivityBillVO queryActivityBill(PartakeReq req) {
        Activity activity = this.getOne(Wrappers.<Activity>lambdaQuery().eq(Activity::getActivityId, req.getActivityId()));
        UserTakeActivityCount userTakeActivityCount = userTakeActivityCountRepository.queryUserTakeActivityCount(req.getuId(),req.getActivityId());

        ActivityBillVO activityBillVO = new ActivityBillVO();
        activityBillVO.setuId(req.getuId());
        activityBillVO.setActivityId(activity.getActivityId());
        activityBillVO.setActivityName(activity.getActivityName());
        activityBillVO.setBeginDateTime(activity.getBeginDateTime());
        activityBillVO.setEndDateTime(activity.getEndDateTime());
        activityBillVO.setStockSurplusCount(activity.getStockSurplusCount());
        activityBillVO.setState(activity.getState());
        activityBillVO.setStrategyId(activity.getStrategyId());
        activityBillVO.setTakeCount(activity.getTakeCount());
        //用户剩余可领取次数
        activityBillVO.setUserTakeLeftCount(userTakeActivityCount.getLeftCount());
        return activityBillVO;
    }

    /**
     * 扣减活动库存数量
     *
     * @param req 参与活动请求
     * @param stockCount 剩余库存数量
     * @return 扣减结果
     */
    @Override
    public StockResult subtractionActivityStockByRedis(PartakeReq req,Integer stockCount) {
        String key = Constants.RedisKey.ACTIVITY_STOCK_COUNT + req.getActivityId();
        //扣减redis库存
        Long increment = redisTemplate.opsForValue().increment(key, -1L);
        //如果扣减后的库存小于0，则补回库存并结束
        if (increment == null || increment < 0) {
            redisTemplate.opsForValue().increment(key, 1L);
            return new StockResult(Constants.ResponseCode.OUT_OF_STOCK.getCode(), Constants.ResponseCode.OUT_OF_STOCK.getInfo());
        }
        //扣减redis库存成，占用【活动id+库存数量】作为锁
        String lockKey = Constants.RedisKey.ACTIVITY_STOCK_LOCK + req.getActivityId() + ":" + increment;
        boolean execute = (boolean) redisTemplate.execute((RedisCallback) connection -> {
            //获取锁
            return connection.setNX(lockKey.getBytes(), String.valueOf(System.currentTimeMillis() + 350L).getBytes());
        });
        if (!execute) {
            log.info("获取锁失败");
            return new StockResult(Constants.ResponseCode.ERR_TOKEN.getCode(), Constants.ResponseCode.ERR_TOKEN.getInfo());
        }
        log.info("获取锁成");
        return new StockResult(Constants.ResponseCode.SUCCESS.getCode(), Constants.ResponseCode.SUCCESS.getInfo(),lockKey,Integer.parseInt(increment.toString()));
    }

    /**
     * 扫描待处理的活动列表，状态为：通过、活动中
     *
     * @param id ID
     * @return 待处理的活动集合
     */
    @Override
    public List<Activity> scanToDoActivityList(Long id) {
        LambdaQueryWrapper<Activity> queryWrapper = Wrappers.<Activity>lambdaQuery()
                //状态为：通过、活动中
                .in(Activity::getState, Constants.ActivityState.PASS.getCode(), Constants.ActivityState.DOING.getCode())
                //id大于当前id
                .gt(Activity::getId, id)
                //按照id升序
                .orderByAsc(Activity::getId);
        return this.list(queryWrapper);
    }

    /**
     * 释放活动库存锁
     *
     * @param stockKey 库存锁
     */
    @Override
    public void recoverActivityCacheStockByRedis(String stockKey) {
        redisTemplate.delete(stockKey);
    }

    /**
     * 更新活动库存
     *
     * @param activityPartakeRecordVO redis中记录的剩余库存
     */
    @Override
    public void updateActivityStock(ActivityPartakeRecordVO activityPartakeRecordVO) {
        LambdaUpdateWrapper<Activity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Activity::getActivityId,activityPartakeRecordVO.getActivityId())
                .set(Activity::getStockSurplusCount,activityPartakeRecordVO.getStockSurplusCount());
        this.update(updateWrapper);
    }
}
